package view;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.swing.JPanel;

import model.general.LoadImage;
import model.general.Location;
import model.general.Util;
import model.object.Boat;
import model.object.Fish;
import model.object.Hook;
import model.object.IObjectAnimate;
import model.option.OptionAddLife;

public class Map extends JPanel implements Runnable, KeyListener {
	private List<IObjectAnimate> listFish = new ArrayList<IObjectAnimate>();
	// private List<ObjectAnimate> listItems = new ArrayList<ObjectAnimate>();
	private Boat boat;
	private Hook hook;

	private static final int PWIDTH = Util.DEFAULT_WIDTH_PANEL; // size of panel
	private static final int PHEIGHT = Util.DEFAULT_HEIGHT_PANEL;

	private Thread animator; // the thread that performs the animation
	private boolean running = false; // used to stop the animation thread
	private boolean isPaused = false;

	private long period; // period between drawing in _nanosecs_

	private long gameStartTime; // when the game started
	private int timeSpentInGame;

	// used at game termination
	private boolean gameOver = false;
	private int score = 0;

	// for displaying messages
	private Font msgsFont;
	private FontMetrics metrics;

	// off-screen rendering
	private Graphics dbg;
	private Image dbImage = null;

	// holds the background image
	private BufferedImage bgImage = null;

	private Random rand = new Random();

	public Map(int period) {
		this.period = period;

		setDoubleBuffered(false);
		setBackground(Color.black);
		this.setSize(PWIDTH, PHEIGHT);
		setFocusable(true);
		requestFocus(); // the JPanel now has focus, so receives key events

		// load the background image
		LoadImage imsLoader = new LoadImage();
		bgImage = imsLoader.getbufferImage("bg.jpg");

		// initialise the clips loader

		// create game sprites
		boat = Boat.getInstance();
		boat.setPnl(this);

		// hook = Hook.getInstance();
		// hook.setPnl(this);

		// create fish
		int w = PWIDTH / 2;
		int h = PHEIGHT / 2;
		Fish f;
		for (int i = 0; i < 1; i++) {
			int x = (int) (w * Math.random() + w);
			int y = (int) (h * Math.random() + h) - 128;
			f = new Fish(x, y, "fish1-left.png", new OptionAddLife(), this);
			listFish.add(f);

		}

		// set up message font
		msgsFont = new Font("SansSerif", Font.BOLD, 24);
		metrics = this.getFontMetrics(msgsFont);

		// add ketlistner
		addKeyListener(this);
	}

	public void gameOver() {
		gameOver = true;
	}

	public void addNotify()
	// wait for the JPanel to be added to the JFrame before starting
	{
		super.addNotify(); // creates the peer
		startGame(); // start the thread
	}

	private void startGame()
	// initialise and start the thread
	{
		if (animator == null || !running) {
			animator = new Thread(this);
			animator.start();
		}
	} // end of startGame()

	// ------------- game life cycle methods ------------
	// called by the JFrame's window listener methods
	public void resumeGame()
	// called when the JFrame is activated / deiconified
	{
		isPaused = false;
	}

	public void pauseGame()
	// called when the JFrame is deactivated / iconified
	{
		isPaused = true;
	}

	public void stopGame()
	// called when the JFrame is closing
	{
		running = false;
	}

	// ----------------------------------------------

	@Override
	public void run() {
		// TODO Auto-generated method stub
		running = true;

		while (running) {
			gameUpdate();
			gameRender();
			paintScreen();
		}

		try {
			Thread.sleep(100);
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}

	private void gameUpdate() {
		if (!isPaused && !gameOver) {
			for (int i = 0; i < listFish.size(); i++) {
				listFish.get(i).updateObject();
				listFish.get(i).move();
			}
		}
	} // end of gameUpdate()

	private void gameRender() {
		if (dbImage == null) {
			dbImage = createImage(PWIDTH, PHEIGHT);
			if (dbImage == null) {
				System.out.println("dbImage is null");
				return;
			} else
				dbg = dbImage.getGraphics();
		}

		// draw the background: use the image or a black colour
		if (bgImage == null) {
			dbg.setColor(Color.black);
			dbg.fillRect(0, 0, PWIDTH, PHEIGHT);
		} else
			dbg.drawImage(bgImage, 0, 0, this);

		// draw game elements
		boat.show(dbg);
		for (int i = 0; i < listFish.size(); i++) {
			listFish.get(i).show(dbg);
		}
		// for (int i = 0; i < listFish.size(); i++) {
		// listItems.get(i).show(dbg);
		// }

		if (gameOver)
			gameOverMessage(dbg);
	} // end of gameRender()

	private void gameOverMessage(Graphics g)
	// center the game-over message in the panel
	{
		String msg = "Game Over. Your score: " + score;

		int x = (PWIDTH - metrics.stringWidth(msg)) / 2;
		int y = (PHEIGHT - metrics.getHeight()) / 2;
		g.setColor(Color.red);
		g.setFont(msgsFont);
		g.drawString(msg, x, y);
	} // end of gameOverMessage()

	private void paintScreen()
	// use active rendering to put the buffered image on-screen
	{
		Graphics g;
		try {
			g = this.getGraphics();
			if ((g != null) && (dbImage != null))
				g.drawImage(dbImage, 0, 0, null);
			g.dispose();
		} catch (Exception e) {
			System.out.println("Graphics context error: " + e);
		}
	} // end of paintScreen()

	@Override
	public void keyPressed(KeyEvent e) {
		move(e);
	}

	@Override
	public void keyReleased(KeyEvent e) {
		// TODO Auto-generated method stub
		move(e);
	}

	public void move(KeyEvent e) {
		if (e.getKeyCode() == KeyEvent.VK_LEFT) {
			boat.moveLeft();

		}
		if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
			boat.moveRight();

		}
		if (e.getKeyCode() == KeyEvent.VK_DOWN) {
			hook.setPnl(this);
			Thread t = new Thread(hook);
			t.start();
		}
	}

	@Override
	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub

	}

}
